import {
  Scene,
  PerspectiveCamera,
  Vector3,
  MOUSE,
  Group,
  RGBAFormat,
  Color,
  Fog,
  CubeCamera,
  MeshStandardMaterial,
  WebGLCubeRenderTarget,
  HalfFloatType,
  Mesh,
  IcosahedronGeometry,
  BoxGeometry,
  CubeReflectionMapping,
  WebGLRenderer,
  StereoCamera,
  Clock,
} from 'three'

import Stats from 'three/examples/jsm/libs/stats.module'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { TransformControls } from 'three/examples/jsm/controls/TransformControls'
import { TEventManager } from './TEventManager'
import { envMapTexture } from './Ttextures'
import { StereoEffect } from 'three/examples/jsm/effects/StereoEffect'
import { AnaglyphEffect } from 'three/examples/jsm/effects/AnaglyphEffect'
import { createComposer } from './TPass'
import { enableAnimation } from './Tanimation'
import { boneContainer, skeletonAnimation, skinnedMesh } from './TSKeleton'

// 3d引擎类
export class TEngine {
  dom
  renderer
  transformControls
  eventManager
  scene
  camera
  constructor(dom) {
    this.dom = dom
    const renderer = new WebGLRenderer({
      antialias: true, //抗锯齿
    }) //webgl渲染器
    renderer.setSize(dom.offsetWidth, dom.offsetHeight, true) //设置渲染器尺寸
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
    renderer.shadowMap.enabled = true //开启阴影渲染

    const scene = new Scene() //实例场景
    envMapTexture.format = RGBAFormat
    envMapTexture.mapping = CubeReflectionMapping
    // scene.background = envMapTexture

    const fog = new Fog() //雾
    fog.color = new Color('rgba(100,200,200,0.1)')
    scene.fog = fog

    const camera = new PerspectiveCamera(
      70,
      dom.offsetWidth / dom.offsetHeight,
      1,
      3000
    ) //实例相机

    camera.position.set(300, 300, 300) //设置相机位置
    camera.lookAt(new Vector3(0, 0, 0)) //相机看向0,0,0
    camera.up = new Vector3(0, 1, 0) //相机朝向

    const stats = Stats() //性能监视器对象
    const statsDom = stats.domElement
    statsDom.style.position = 'fixed'
    statsDom.style.top = '0'
    statsDom.style.left = 'unset'
    statsDom.style.right = '5px'

    const orbitControls = new OrbitControls(camera, renderer.domElement) //初始轨道控制器
    // orbitControls.autoRotate = true//自动旋转
    orbitControls.mouseButtons = {
      LEFT: null,
      MIDDLE: MOUSE.DOLLY,
      RIGHT: MOUSE.ROTATE,
    } //设置鼠标对轨道控制器的操作

    // 初始化变换控制器
    const transformControls = new TransformControls(camera, renderer.domElement)
    let transing = false //判断此次鼠标事件是否是变换事件
    transformControls.addEventListener('mouseDown', () => {
      transing = true
    })
    const eventManager = new TEventManager({
      dom: renderer.domElement,
      scene,
      camera,
    })

    // 创建立方体相机
    const cubeRenderTarget = new WebGLCubeRenderTarget(256)
    cubeRenderTarget.texture.type = HalfFloatType
    const cubeCamare = new CubeCamera(1, 1000, cubeRenderTarget)
    scene.add(cubeCamare)

    const material = new MeshStandardMaterial({
      envMap: cubeRenderTarget.texture,
      roughness: 0,
      metalness: 1,
    })
    const material2 = new MeshStandardMaterial({
      roughness: 1,
      metalness: 0,
    })
    const sphere = new Mesh(new IcosahedronGeometry(15, 8), material)
    const cube = new Mesh(new BoxGeometry(15, 15, 15), material2)
    scene.add(cube)
    scene.add(sphere)
    sphere.position.set(50, 50, 50)
    cubeCamare.position.set(50, 50, 50)
    sphere.scale.set(2, 2, 2)
    cube.position.set(50, 50, -50)
    cube.scale.set(2, 2, 2)

    const effect = new StereoEffect(renderer)
    effect.setSize(dom.offsetWidth, dom.offsetHeight)

    const angalyphEffect = new AnaglyphEffect(renderer)
    angalyphEffect.setSize(dom.offsetWidth, dom.offsetHeight)

    // 创建效果合成器
    const composerRender = new createComposer(
      renderer,
      dom.offsetWidth,
      dom.offsetHeight,
      scene,
      camera
    )

    let cacheObject = null
    eventManager.addEventListener('mousemove', (event) => {
      //   console.log('global mousemove')
      const intersection = event.intersection
      if (intersection.length) {
        const object = intersection[0].object

        // 对比新老物体
        if (object === cacheObject) {
          return
        } else if (object !== cacheObject && cacheObject) {
          // 添加一个颜色的S通道变化(变暗)
          // cacheObject.material.color.multiplyScalar(0.5)
        }

        if (object.material) {
          // 添加一个颜色的S通道变化(变亮)
          // object.material.color.multiplyScalar(2)
          cacheObject = object
        }
      } else {
        if (cacheObject) {
          // cacheObject.material.color.multiplyScalar(0.5)
        }
        cacheObject = null
      }
    })
    // 添加按键事件，用于切换控制器模式
    document.addEventListener('keyup', (event) => {
      if (event.key === 'e') {
        transformControls.mode = 'scale'
        return
      }
      if (event.key === 'r') {
        transformControls.mode = 'rotate'
        return
      }
      if (event.key === 't') {
        transformControls.mode = 'translate'
        return
      }
    })
    eventManager.addEventListener('click', (event) => {
      if (transing) {
        transing = false
        return
      }
      if (event.intersection.length) {
        // 获取最外面的物体
        const object = event.intersection[0].object
        if (object.type === 'TransformControlsPlane') {
          transformControls.detach()
          scene.remove(transformControls)
        } else {
          scene.add(transformControls)
          // 将获取的物体绑定到控制器
          transformControls.attach(
            object.parent instanceof Group ? object.parent : object
          )
          composerRender.outlinePass.selectedObjects = [
            object.parent instanceof Group ? object.parent : object,
          ] //数组
        }
      } else {
        transformControls.detach()
        scene.remove(transformControls)
        composerRender.outlinePass.selectedObjects = []
      }
    })

    // 立体相机
    const stereoCamera = new StereoCamera()
    stereoCamera.aspect = 0.5

    const composerRender2 = new createComposer(
      renderer,
      dom.offsetWidth,
      dom.offsetHeight,
      scene,
      stereoCamera.cameraL
    )
    function stereoCameraRender(bol) {
      if (!bol) {
        composerRender.composer.render()
        return
      }
      scene.updateMatrixWorld()
      if (camera.parent === null) {
        camera.updateMatrixWorld()
      }
      if (renderer.autoClear) {
        renderer.clear()
      }

      // 开启WebGL剪裁功能，如果不开启，.setScissor方法设置的范围不起作用
      renderer.setScissorTest(true)
      renderer.setScissor(0, 0, dom.offsetWidth / 2, dom.offsetHeight)
      renderer.setViewport(0, 0, dom.offsetWidth / 2, dom.offsetHeight)
      composerRender2.composer.render()

      renderer.setScissor(
        dom.offsetWidth / 2,
        0,
        dom.offsetWidth / 2,
        dom.offsetHeight
      )
      renderer.setViewport(
        dom.offsetWidth / 2,
        0,
        dom.offsetWidth / 2,
        dom.offsetHeight
      )
      renderer.render(scene, stereoCamera.cameraR)
      renderer.setScissorTest(false)
    }

    // 添加动画
    let playable = false
    const mixer = enableAnimation(cube, playable)
    const skeletionMixer = skeletonAnimation(!playable)
    const clock = new Clock()

    // 添加骨骼模型动画
    scene.add(skinnedMesh)
    // console.log(skinnedMesh)
    scene.add(boneContainer)
    // console.log(boneContainer)

    // 循环渲染
    const renderFun = () => {
      if (playable && mixer) {
        mixer.update(clock.getDelta())
      }
      skeletionMixer.update(clock.getDelta())
      stereoCameraRender(false)
      // composerRender.composer.render()
      // renderer.render(scene, camera) //渲染器渲染场景、相机
      const { x, y, z } = sphere.position
      cubeCamare.position.set(x, y, z)
      cubeCamare.update(renderer, scene)
      stereoCamera.update(camera)

      orbitControls.update() //开启自动旋转后，在渲染前更新轨道控制器
      stats.update() //性能监视器更新
      requestAnimationFrame(renderFun)
    }
    renderFun()

    dom.appendChild(renderer.domElement) //将渲染器插入dom对象中
    dom.appendChild(statsDom) //添加监视器dom对象

    this.renderer = renderer
    this.scene = scene
    this.transformControls = transformControls
    this.camera = camera
    this.eventManager = eventManager
  }

  addObject(...object) {
    object.forEach((ele) => {
      this.scene.add(ele)
    })
  }
}
